package cn.com.twoke.easyproject.aspect.request.lock.generator;

import cn.com.twoke.easyproject.aspect.request.lock.RequestKeyObject;
import cn.com.twoke.easyproject.aspect.request.lock.RequestKeyParam;
import cn.com.twoke.easyproject.aspect.request.lock.RequestLock;
import cn.com.twoke.easyproject.aspect.request.lock.RequestLockKeyGenerator;
import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@Slf4j
public class BasicKeyGenerator implements RequestLockKeyGenerator {

    @Override
    public String generateKey(ProceedingJoinPoint joinPoint, RequestLock requestLock) {
        //获取连接点的方法签名对象
        MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
        //Method对象
        Method method = methodSignature.getMethod();
        //获取方法参数
        final Object[] args = joinPoint.getArgs();
        //获取Method对象上所有的注解
        final Parameter[] parameters = method.getParameters();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < parameters.length; i++) {
            if (parameters[i].isAnnotationPresent(RequestKeyParam.class)) {
                doKeyParam(sb, requestLock, parameters[i], args[i]);
            } else if (parameters[i].isAnnotationPresent(RequestKeyObject.class) ||
                args[i].getClass().isAnnotationPresent(RequestKeyObject.class)) {
                doKeyObject(sb, requestLock, parameters[i], args[i]);
            } else {
                log.info("忽略参数锁定 {}", parameters[i].getName());
            }
        }
        return sb.toString();
    }

    private void doKeyObject(StringBuilder sb, RequestLock requestLock, Parameter parameter, Object object) {
        //获取注解类中所有的属性字段
        final Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            //判断字段上是否有RequestKeyParam注解
            final RequestKeyParam annotation = field.getAnnotation(RequestKeyParam.class);
            //如果没有，跳过
            if (annotation == null) {
                continue;
            }
            //如果有，设置Accessible为true（为true时可以使用反射访问私有变量，否则不能访问私有变量）
            field.setAccessible(true);
            //如果属性是RequestKeyParam注解，则拼接 连接符" & + RequestKeyParam"
            sb.append(requestLock.delimiter()).append(parameter.getName())
                    .append(".")
                    .append(field.getName())
                    .append("=")
                    .append(ReflectionUtils.getField(field, object));
        }
    }

    /**
     * 处理key
     * @param sb
     * @param requestLock
     * @param parameter
     * @param arg
     */
    private void doKeyParam(StringBuilder sb, RequestLock requestLock, Parameter parameter, Object arg) {
        //如果属性是RequestKeyParam注解，则拼接 连接符 "& + RequestKeyParam"
        sb.append(requestLock.delimiter()).append(parameter.getName()).append("=").append(arg);
    }


}
